const { ipcMain, app } = require('electron');
const path = require('path');
const fs = require('fs').promises;
const fsSync = require('fs');
const archiver = require('archiver');
const AdmZip = require('adm-zip');
const crypto = require('crypto');
const { getDb, createCaseDatabase } = require('../database');

function registerCaseHandlers(projectRoot) {
    const db = getDb();

    // 获取案件列表
    ipcMain.handle('get-cases', async (event) => {
        return new Promise((resolve, reject) => {
            const sql = 'SELECT * FROM cases ORDER BY created_time DESC';
            db.all(sql, [], (err, rows) => {
                if (err) {
                    console.error('Failed to query case data:', err.message);
                    reject(err);
                } else {
                    resolve(rows);
                }
            });
        });
    });

    // 创建案件
    ipcMain.handle('create-case', async (event, caseData) => {
        return new Promise((resolve, reject) => {
            const now = new Date();
            const timestamp = `${now.getFullYear()}${String(now.getMonth() + 1).padStart(2, '0')}${String(now.getDate()).padStart(2, '0')}`;

            const countSql = `SELECT COUNT(*) as count FROM cases WHERE case_number LIKE 'AJ${timestamp}%'`;
            db.get(countSql, [], (err, row) => {
                if (err) {
                    reject(err);
                    return;
                }

                const sequenceNum = String((row.count || 0) + 1).padStart(3, '0');
                const caseNumber = `AJ${timestamp}${sequenceNum}`;

                const caseStartTime = caseData.case_start_time || caseData.created_time || new Date().toISOString().slice(0, 19).replace('T', ' ');
                const createdTime = new Date().toISOString().slice(0, 19).replace('T', ' ');

                const insertSql = `INSERT INTO cases (case_name, case_status, case_number, created_time, case_start_time, password, description, db_path) VALUES (?, ?, ?, ?, ?, ?, ?, ?)`;

                db.run(insertSql, [
                    caseData.case_name,
                    caseData.case_status,
                    caseNumber,
                    createdTime,
                    caseStartTime,
                    caseData.password || null,
                    caseData.description || null,
                    ''  // 临时值，稍后更新
                ], async function (err) {
                    if (err) {
                        reject(err);
                    } else {
                        try {
                            // 为新案件创建独立数据库文件
                            const dbPath = await createCaseDatabase(projectRoot, caseNumber, this.lastID);

                            // 更新案件记录，设置数据库路径
                            const updateSql = `UPDATE cases SET db_path = ? WHERE id = ?`;
                            await new Promise((updateResolve, updateReject) => {
                                db.run(updateSql, [dbPath, this.lastID], (err) => {
                                    if (err) updateReject(err);
                                    else updateResolve();
                                });
                            });

                            resolve({
                                id: this.lastID,
                                case_number: caseNumber,
                                db_path: dbPath
                            });
                        } catch (dbErr) {
                            // 如果创建独立数据库失败，删除已创建的案件记录
                            const deleteSql = `DELETE FROM cases WHERE id = ?`;
                            db.run(deleteSql, [this.lastID], () => { });
                            reject(dbErr);
                        }
                    }
                });
            });
        });
    });

    // 更新案件
    ipcMain.handle('update-case', async (event, caseData) => {
        return new Promise((resolve, reject) => {
            let updateSql = '';
            let params = [];

            if (caseData.hasOwnProperty('closed_status') && !caseData.case_name) {
                updateSql = `UPDATE cases SET closed_status = ? WHERE id = ?`;
                params = [caseData.closed_status, caseData.id];
            }
            else if (caseData.hasOwnProperty('password') && !caseData.case_name) {
                updateSql = `UPDATE cases SET password = ? WHERE id = ?`;
                params = [caseData.password, caseData.id];
            }
            else {
                if (caseData.hasOwnProperty('case_start_time')) {
                    updateSql = `UPDATE cases SET case_name = ?, case_status = ?, description = ?, case_start_time = ? WHERE id = ?`;
                    params = [caseData.case_name, caseData.case_status, caseData.description || null, caseData.case_start_time, caseData.id];
                } else {
                    updateSql = `UPDATE cases SET case_name = ?, case_status = ?, description = ? WHERE id = ?`;
                    params = [caseData.case_name, caseData.case_status, caseData.description || null, caseData.id];
                }
            }

            db.run(updateSql, params, function (err) {
                if (err) {
                    console.error('Failed to update case data:', err.message);
                    reject(err);
                } else {
                    resolve({ changes: this.changes });
                }
            });
        });
    });

    // 删除案件
    ipcMain.handle('delete-case', async (event, caseId) => {
        return new Promise((resolve, reject) => {
            const getCaseSql = `SELECT db_path, case_number FROM cases WHERE id = ?`;
            db.get(getCaseSql, [caseId], async (err, row) => {
                if (err) {
                    console.error('Failed to get case info for deletion:', err);
                    reject(err);
                    return;
                }

                if (!row) {
                    reject(new Error('Case not found'));
                    return;
                }

                const dbPath = row.db_path;

                const deleteSql = `DELETE FROM cases WHERE id = ?`;
                db.run(deleteSql, [caseId], async function (err) {
                    if (err) {
                        console.error('Failed to delete case from database:', err);
                        reject(err);
                    } else {
                        if (dbPath) {
                            try {
                                if (await fileExists(dbPath)) {
                                    await fs.unlink(dbPath);
                                    console.log(`Deleted case database file: ${dbPath}`);
                                }

                                const attachmentsDir = path.join(projectRoot, 'attachments', `case_${caseId}`);
                                if (await fileExists(attachmentsDir)) {
                                    await fs.rm(attachmentsDir, { recursive: true, force: true });
                                    console.log(`Deleted case attachments directory: ${attachmentsDir}`);
                                }
                            } catch (fsErr) {
                                console.error('Failed to delete case files:', fsErr);
                            }
                        }
                        resolve({ changes: this.changes });
                    }
                });
            });
        });
    });

    // 导出案件
    ipcMain.handle('export-case', async (event, caseId, exportOptions = {}) => {
        try {
            const userDataPath = app.getPath('userData');
            const tempDir = path.join(userDataPath, 'temp_exports');

            await fs.mkdir(tempDir, { recursive: true });

            const caseInfo = await getCaseInfo(db, caseId);
            if (!caseInfo) throw new Error('案件不存在');
            if (!caseInfo.db_path) throw new Error('案件数据库路径未设置');
            if (!fsSync.existsSync(caseInfo.db_path)) throw new Error('案件数据库文件不存在');

            const caseExportDir = path.join(tempDir, `case_${caseId}`);
            await fs.mkdir(caseExportDir, { recursive: true });

            const sourceDbPath = caseInfo.db_path;
            const targetDbPath = path.join(caseExportDir, 'case.db');
            await fs.copyFile(sourceDbPath, targetDbPath);

            const attachmentsDir = path.join(caseExportDir, 'attachments');
            await fs.mkdir(attachmentsDir, { recursive: true });

            const metadata = {
                version: '1.0',
                case_id: `case_${caseId}`,
                case_number: caseInfo.case_number,
                case_name: caseInfo.case_name,
                created_time: caseInfo.created_time,
                export_time: new Date().toISOString(),
                exporter: exportOptions.exporter || 'Unknown',
                description: caseInfo.description,
                encrypted: !!caseInfo.password,
                encryption_method: caseInfo.password ? 'AES-256' : null,
                schema_version: '1.0'
            };

            await fs.writeFile(path.join(caseExportDir, 'metadata.json'), JSON.stringify(metadata, null, 2));

            const manifest = await createFileManifest(caseExportDir);
            await fs.writeFile(path.join(caseExportDir, 'manifest.json'), JSON.stringify(manifest, null, 2));

            let finalExportDir = caseExportDir;
            let finalFileName = `案件_${caseInfo.case_number}.case`;

            if (exportOptions.encryptPackage) {
                // finalExportDir = await encryptCasePackage(caseExportDir, exportOptions.password);
                finalFileName = `案件_${caseInfo.case_number}_encrypted.case`;
            }

            const exportPath = path.join(exportOptions.exportPath || userDataPath, finalFileName);
            await createCasePackage(finalExportDir, exportPath);

            await fs.rm(tempDir, { recursive: true, force: true });

            return { success: true, filePath: exportPath, fileName: finalFileName };

        } catch (error) {
            console.error('Failed to export case:', error);
            throw error;
        }
    });

    // 导入案件
    ipcMain.handle('import-case', async (event, importFilePath, importOptions = {}) => {
        try {
            const userDataPath = app.getPath('userData');
            const tempDir = path.join(userDataPath, 'temp_imports');
            const casesDir = path.join(projectRoot, 'cases');

            await fs.mkdir(tempDir, { recursive: true });

            const zip = new AdmZip(importFilePath);
            const extractPath = path.join(tempDir, 'extracted');
            zip.extractAllTo(extractPath, true);

            const manifestPath = path.join(extractPath, 'manifest.json');
            if (await fileExists(manifestPath)) {
                const manifestContent = await fs.readFile(manifestPath, 'utf8');
                const manifest = JSON.parse(manifestContent);
                const isValid = await verifyFileIntegrity(extractPath, manifest);
                if (!isValid && !importOptions.ignoreIntegrity) {
                    throw new Error('案件包文件完整性验证失败');
                }
            }

            const metadataPath = path.join(extractPath, 'metadata.json');
            const metadataContent = await fs.readFile(metadataPath, 'utf8');
            const metadata = JSON.parse(metadataContent);

            const existingCase = await new Promise((resolve, reject) => {
                const checkSql = `SELECT id FROM cases WHERE case_number = ? OR (description = ? AND case_name = ?)`;
                db.get(checkSql, [metadata.case_number, metadata.description, metadata.case_name], (err, row) => {
                    if (err) reject(err);
                    else resolve(row);
                });
            });

            if (existingCase) {
                throw new Error(`Case "${metadata.case_name}" already exists, cannot import duplicate`);
            }

            const newCaseId = await createNewCaseFromImport(db, metadata);

            const sourceDbPath = path.join(extractPath, 'case.db');
            const targetDbPath = path.join(casesDir, `${metadata.case_number}_id${newCaseId}.db`);
            await fs.copyFile(sourceDbPath, targetDbPath);

            await new Promise((resolve, reject) => {
                const updateSql = `UPDATE cases SET db_path = ? WHERE id = ?`;
                db.run(updateSql, [targetDbPath, newCaseId], (err) => {
                    if (err) reject(err);
                    else resolve();
                });
            });

            const sourceAttachmentsDir = path.join(extractPath, 'attachments');
            if (await fileExists(sourceAttachmentsDir)) {
                const targetAttachmentsDir = path.join(projectRoot, 'attachments', `case_${newCaseId}`);
                await fs.mkdir(targetAttachmentsDir, { recursive: true });
                await fs.cp(sourceAttachmentsDir, targetAttachmentsDir, { recursive: true });
            }

            await fs.rm(tempDir, { recursive: true, force: true });

            return { success: true, caseId: newCaseId, caseName: metadata.case_name, caseNumber: metadata.case_number };

        } catch (error) {
            console.error('Failed to import case:', error);
            throw error;
        }
    });
}

// 辅助函数
function getCaseInfo(db, caseId) {
    return new Promise((resolve, reject) => {
        const sql = `SELECT * FROM cases WHERE id = ?`;
        db.get(sql, [caseId], (err, row) => {
            if (err) reject(err);
            else resolve(row);
        });
    });
}

async function fileExists(filePath) {
    try {
        await fs.access(filePath);
        return true;
    } catch {
        return false;
    }
}

async function createFileManifest(directory) {
    const manifest = { files: {}, created: new Date().toISOString() };
    async function scanDirectory(dir, baseDir = dir) {
        const files = await fs.readdir(dir);
        for (const file of files) {
            const filePath = path.join(dir, file);
            const stat = await fs.stat(filePath);
            if (stat.isDirectory()) {
                await scanDirectory(filePath, baseDir);
            } else {
                const relativePath = path.relative(baseDir, filePath);
                const fileHash = await calculateFileHash(filePath);
                manifest.files[relativePath] = { size: stat.size, hash: fileHash, modified: stat.mtime.toISOString() };
            }
        }
    }
    await scanDirectory(directory);
    return manifest;
}

async function calculateFileHash(filePath) {
    const hash = crypto.createHash('sha256');
    const stream = fsSync.createReadStream(filePath);
    return new Promise((resolve, reject) => {
        stream.on('data', data => hash.update(data));
        stream.on('end', () => resolve(hash.digest('hex')));
        stream.on('error', reject);
    });
}

async function createCasePackage(sourceDir, outputPath) {
    return new Promise((resolve, reject) => {
        const output = fsSync.createWriteStream(outputPath);
        const archive = archiver('zip', { zlib: { level: 9 } });
        output.on('close', resolve);
        archive.on('error', reject);
        archive.pipe(output);
        archive.directory(sourceDir, false);
        archive.finalize();
    });
}

async function verifyFileIntegrity(directory, manifest) {
    try {
        for (const [relativePath, fileInfo] of Object.entries(manifest.files)) {
            const filePath = path.join(directory, relativePath);
            if (!(await fileExists(filePath))) return false;
            const currentHash = await calculateFileHash(filePath);
            if (currentHash !== fileInfo.hash) return false;
        }
        return true;
    } catch {
        return false;
    }
}

function createNewCaseFromImport(db, metadata) {
    return new Promise((resolve, reject) => {
        const now = new Date();
        const timestamp = `${now.getFullYear()}${String(now.getMonth() + 1).padStart(2, '0')}${String(now.getDate()).padStart(2, '0')}`;
        const countSql = `SELECT COUNT(*) as count FROM cases WHERE case_number LIKE 'AJ${timestamp}%'`;
        db.get(countSql, [], (err, row) => {
            if (err) { reject(err); return; }
            const sequenceNum = String((row.count || 0) + 1).padStart(3, '0');
            const caseNumber = `AJ${timestamp}${sequenceNum}`;
            const insertSql = `INSERT INTO cases (case_name, case_status, case_number, created_time, case_start_time, password, description, db_path) VALUES (?, ?, ?, ?, ?, ?, ?, ?)`;
            db.run(insertSql, [
                metadata.case_name, '初核', caseNumber, metadata.created_time, metadata.created_time,
                metadata.encrypted ? 'encrypted' : null, metadata.description, ''
            ], function (err) {
                if (err) reject(err);
                else resolve(this.lastID);
            });
        });
    });
}

module.exports = { registerCaseHandlers };
